﻿using System;
using System.Collections.Generic;
using System.Text;
using DevExpress.Persistent.Base;
using DevExpress.Xpo;
using DevExpress.Data.Filtering;
using DevExpress.ExpressApp.DC;
using DevExpress.Persistent.Validation;
using DevExpress.ExpressApp;
using DevExpress.ExpressApp.ConditionalAppearance;
using DevExpress.ExpressApp.Utils;
using DevExpress.ExpressApp.SystemModule;
using DomainComponents.Common;
using System.ComponentModel;

namespace DomainComponents.XCRM {
    public enum SaleStage {
        Unknown = 0,
        Lead = 1,
        Opportunity = 2,
        Quote = 3,
        Order = 4,
        Invoice = 5,
        Sale = 6
    }

    [DomainComponent]
    public interface ISaleStageHistory {
        [DevExpress.ExpressApp.DC.Aggregated, VisibleInDetailView(false)]
        IList<ILeadHistoryRecord> LeadHistoryRecords { get; }
        ILeadHistoryRecord FindLeadHistoryRecord(SaleStage saleStage);
    }

    [DomainComponent]
    public interface ISaleStageHistoryTarget {
        [System.ComponentModel.Browsable(false)]
        SaleStage SaleStage { get; }
        [System.ComponentModel.Browsable(false)]
        ISaleStageHistory History { get; }
    }

    [DomainLogic(typeof(ISaleStageHistoryTarget))]
    public class ISaleStageHistoryTargetLogic {
        public static void OnSaving(ISaleStageHistoryTarget saleStageHistoryTarget, IObjectSpace os) {
            if(saleStageHistoryTarget.History != null) {
                bool addHistoryRecord = true;
                foreach(ILeadHistoryRecord historyRecord in saleStageHistoryTarget.History.LeadHistoryRecords) {
                    if(historyRecord.SaleStage == saleStageHistoryTarget.SaleStage)
                        addHistoryRecord = false;
                }
                if(addHistoryRecord) {
                    ILeadHistoryRecord historyRecord = os.CreateObject<ILeadHistoryRecord>();
                    historyRecord.SaleStage = saleStageHistoryTarget.SaleStage;
                    saleStageHistoryTarget.History.LeadHistoryRecords.Add(historyRecord);
                }
            }
        }
        private static bool GetLeadFrom(ILeadTarget leadTarget, out ISaleStageHistory result) {
            result = null;
            if(leadTarget != null) {
                result = leadTarget.SourceLead as ISaleStageHistory;
                return true;
            }
            return false;
        }
        private static bool GetLeadFrom(IOpportunityTarget opportunityTarget, out ISaleStageHistory result) {
            result = null;
            if(opportunityTarget != null) {
                return GetLeadFrom(opportunityTarget.SourceOpportunity as ILeadTarget, out result);
            }
            return false;
        }
        public static ISaleStageHistory Get_History(ISaleStageHistoryTarget saleStageHistoryTarget) {
            ISaleStageHistory result = null;
            if(GetLeadFrom(saleStageHistoryTarget as ILeadTarget, out result)) {
                return result;
            }
            if(GetLeadFrom(saleStageHistoryTarget as IOpportunityTarget, out result)) {
                return result;
            }
            return null;
        }
        public static SaleStage Get_SaleStage(ISaleStageHistoryTarget target) {
            if(target is IOpportunity) {
                return SaleStage.Opportunity;
            }
            else if(target is IQuote) {
                return SaleStage.Quote;
            }
            else if(target is IOrder) {
                return SaleStage.Order;
            }
            else if(target is IInvoice) {
                return ((IInvoice)target).Status == InvoiceStatus.Completed ? 
                    SaleStage.Sale : SaleStage.Invoice;
            }
            return SaleStage.Unknown;
        }
    }

    [DomainLogic(typeof(ISaleStageHistory))]
    public class LeadSaleStageHistoryLogic {
        public static void AfterConstruction(ISaleStageHistory self, IObjectSpace os) {
            ILeadHistoryRecord historyRecord = os.CreateObject<ILeadHistoryRecord>();
            historyRecord.SaleStage = SaleStage.Lead;
            ((ISaleStageHistory)self).LeadHistoryRecords.Add(historyRecord);
        }
        public static ILeadHistoryRecord FindLeadHistoryRecord(ISaleStageHistory history, SaleStage saleStage) {
            List<ILeadHistoryRecord> historyRecords = new List<ILeadHistoryRecord>(history.LeadHistoryRecords);
            ILeadHistoryRecord result = null;
            foreach(ILeadHistoryRecord record in historyRecords) {
                if(record.SaleStage == saleStage) {
                    if(result != null) {
                        throw new InvalidOperationException("Lead history item is duplicated.");
                    }
                    result = record;
                }
            }
            return result;
        }
    }

    [DomainComponent]
    public interface ILeadHistoryRecord {
        SaleStage SaleStage { get; set; }
        int StageOrder { get; }
    }

    [DomainLogic(typeof(ILeadHistoryRecord))]
    public class LeadHistoryRecordLogic {
        public static int Get_StageOrder(ILeadHistoryRecord record) {
            return (int)record.SaleStage;
        }
    }
}
